from threading import Thread
import pyqtgraph as pg
import MySQLdb, re

import requests
from PySide6 import QtCore
from PySide6.QtWidgets import (QHBoxLayout, QVBoxLayout, QApplication, QFrame, QLabel, QPushButton, QPlainTextEdit,
                               QMainWindow, QWidget, QLineEdit, QFormLayout, QGridLayout, QTextEdit, QMessageBox,
                               QComboBox, QTableWidget, QTableWidgetItem, QSizePolicy, QDateEdit, )
from PySide6.QtCore import Qt, QSize, QObject, Signal, QDate


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        # 连接数据库  #################################
        connection = MySQLdb.connect(
            host='localhost',
            user='root',
            password='139381lj',
            db="byhy",
            charset="utf8",
            auth_plugin='mysql_native_password'
        )
        self.c = connection.cursor()
        ##############################################
        main_window = QWidget(self)
        self.setCentralWidget(main_window)
        self.l = []
        # 设置一个垂直布局作为最外层的布局
        main_vl = QVBoxLayout(main_window)

        # 设置上部的‘获取最新数据’按钮，“输入股票名称”文案，输入框，支持模糊搜索数据展示的下拉
        # 新增水平布局
        upper_hl = QHBoxLayout()
        main_vl.addLayout(upper_hl)
        # 设置按钮
        get_latest_info = QPushButton('获取最新数据')
        upper_hl.addWidget(get_latest_info)
        # 设置表单：“输入股票名称”文案，输入框
        stock_name_form = QFormLayout()
        stock_name_form.setHorizontalSpacing(20)  # 设置水平间距
        self.stock_name = QLineEdit()  # 设置单行文本框
        stock_name_form.addRow(QLabel('输入股票名字或者代码'), self.stock_name)
        upper_hl.addLayout(stock_name_form)  # 把表单加到上部的布局中
        # 设置下拉
        self.vague_data = QComboBox()  # 设置下拉对象
        upper_hl.addWidget(self.vague_data)  # 加到上部布局

        # 设置下部时间范围，支持点击弹出日历进行选择开始和结束时间，获取按钮，展示具体数据
        bottom_vl = QVBoxLayout()  #
        main_vl.addLayout(bottom_vl)
        time_hl = QHBoxLayout()
        bottom_vl.addLayout(time_hl)
        self.start = QLabel('时间范围')  # 添加时间标签
        self.start_date = QDateEdit()  # 添加日期选择控件
        self.start_date.setCalendarPopup(True)  # 启用日历弹窗
        self.start_date.setDate(QDate.currentDate())  # 默认展示当前日期
        self.end_date = QDateEdit()
        self.end_date.setCalendarPopup(True)
        self.end_date.setDate(QDate.currentDate())
        self.get_stock_info = QPushButton("获取")
        self.stock_show = QPlainTextEdit()
        time_hl.addWidget(self.start)
        time_hl.addWidget(self.start_date)
        time_hl.addWidget(self.end_date)
        time_hl.addWidget(self.get_stock_info)
        bottom_vl.addWidget(self.stock_show)

        # 设置下部的图像展示区域，根据中间的具体数据展示图像
        pw = pg.plot()
        pw.setBackground('black')  # 设置背景颜色
        pw.showGrid(x=True, y=True)  # 显示表格线
        pw.setLabel('left', '收盘价')  # 设置左侧标签
        # 创建 PlotDataItem ，这种类型是画 曲线 Curve 和 散列点 scatter plots 的
        self.curve = pw.plot(pen=pg.mkPen('w'))  # 线条颜色
        self.date = []
        self.price = []
        self.curve.setData(  # 设置图像中的数据
            self.date,
            self.price
        )
        bottom_vl.addWidget(pw)  # 把图像框加到下部垂直布局中
        stock_info_hl = QHBoxLayout()
        bottom_vl.addLayout(stock_info_hl)
        stock_info = QLabel('当前股票信息')
        stock_info_hl.addWidget(stock_info)
        self.bottom_label = QLabel()  # 设置一个空标签用于输入股票信息
        stock_info_hl.addWidget(self.bottom_label)
        stock_info_hl.addStretch()  # 设置一个弹簧，把上边的2个标签挤到左边

        # 连接信号
        self.stock_name.textChanged.connect(self.search_name)  # 实时获取编辑输入框的中的内容
        self.get_stock_info.clicked.connect(self.get_history_stock)
        self.curve.scene().sigMouseMoved.connect(self.mouse_move)

    ##########################################################

    # 获取股票名字和代码最新数据，保存到数据库中
    def save_name_code(self):
        pass

    # 获取输入框中的值，进行数据库搜索，返回结果给下拉
    def search_name(self):
        self.l = []  # 重置列表
        text = self.stock_name.text()  # 获取编辑后的内容
        if text.isdigit():  # 判断是否是数字
            self.c.execute(
                f'select * from byhy.stock where code like "%{text}%"'
            )
        else:
            self.c.execute(
                f'select * from byhy.stock where name like "%{text}%"'
            )
        numberrows = self.c.rowcount  # 获取返回的行数
        for t in range(numberrows):
            row = self.c.fetchone()  # 获取返回的结果
            s = f'{row[1]}({row[2]})'
            self.l.append(s)  # 添加到列表
        print(self.l)
        self.vague_data.clear()  # 先清空下拉中的历史数据
        self.vague_data.addItems(self.l)  # 把列表中获取的数据添加为下拉的选项

    # 获取当前选中时间的股票信息，展示在文本框中
    def get_history_stock(self):
        result = ''
        search_stock = self.vague_data.currentText()  # 获取当前下拉中选中的文本
        e = re.findall(r'\d+', search_stock)  # “\d”只取数字，“+”匹配多次，不包含1次
        code = f'cn_{e[0]}'
        start_date = self.start_date.date()  # 取出时间控件的日期
        end_date = self.end_date.date()  # 取出时间控件的日期
        start_date_str = start_date.toString('yyyyMMdd')  # 设置格式，M要大写
        end_date_str = end_date.toString('yyyyMMdd')
        url = 'http://q.stock.sohu.com/hisHq'
        params = {
            'code': code,
            'start': start_date_str,
            'end': end_date_str,
            'stat': 1,
            'order': 'A',
            'period': 'd'
        }
        response = requests.get(url=url, params=params)
        res = response.json()
        print(res)

        for l in res[0]['hq']:  # 取出来日期，开盘，收盘，涨跌，涨幅，最低，最高，成交量，成交额，换手。
            self.date.append(l[0])  # 把日期添加到列表
            self.price.append(float(l[2]))  # 把收盘价转换为浮点数添加到列表中
            result += f'{l}\n'  # 结果换行展示
        x = []
        for i in range(len(self.date)):  # 把date列表中数据，用index代替
            x.append(i)
        self.stock_show.setPlainText(result)
        self.curve.setData(  # 重置图像中的数据
            x,
            self.price
        )

    # 获取实时鼠标的位置
    def mouse_move(self, pos):
        # 参数pos 是像素坐标，需要 转化为  刻度坐标
        act_pos = self.curve.mapFromScene(pos)
        # QPointF 是一个类，表示二维平面上的一个浮点坐标点（包含 x 和 y 值）
        # sigMouseMoved 信号传递的参数可能是 QPointF 类型，但某些情况下可能传入其他类型（如 None 或意外数据）
        if type(act_pos) != QtCore.QPointF:
            return
        x, y = act_pos.x(), act_pos.y()  # 获取x，y轴的坐标值
        if int(x) + 0.5 <= x < int(x) + 1.5:
            x_index = int(x) + 1
        else:
            x_index = int(x)
        self.bottom_label.setText(
            f'{self.date[x_index]}  :   {self.price[x_index]}（收盘价）'
        )


app = QApplication()
win = MainWindow()
win.show()
app.exec()
